
#include <BLine>
#include <BIcon>
#include <BFile>
#include <BStyle>
#include <BPainter>
#include <BMouseEvent>

#include <BMenu>
#include <BLabel>
#include <BButton>
#include <BSlider>
#include <BCheckBox>
#include <BSpinBox>
#include <BRealSpinBox>
#include <BGroupBox>

#include <BHBoxLayout>
#include <BVBoxLayout>
#include <BGridLayout>
#include <BDockLayout>

#include <BFileDialog>
#include <BColorDialog>
#include <BSystem>
#include <BApplication>

#include "MarkChartView.h"

MarkChartView::MarkChartView(const BString& title, BWidget* parent) : ChartView(title, parent)
{
	createFileMenu();
	createContentMenu();
	createSettingMenu();
	createCenterMenu();

	BHBoxLayout* topLayout = new BHBoxLayout(this, Part_Top);
	{
		_buttonLayout = new BHBoxLayout();

		_indexLabel = new BLabel("");
		_indexLabel->setRadius(10);
		_indexLabel->setBorder(1);
		_xLineEdit = new BLineEdit();
		_yLineEdit = new BLineEdit();
		_setAxisButton = new BButton();
		_setAxisButton->setName("setaxis");

		_fileButton = new BButton("file");
		_fileButton->setName("filebutton");
		_fileButton->setForm(Form_IconAlone);
		_fileButton->setMenu(_fileMenu);

		_contentButton = new BButton("Contents");
		_contentButton->setForm(Form_IconAlone);
		_contentButton->setMenu(_contentMenu);

		_settingButton = new BButton("Setting");
		_settingButton->setForm(Form_IconAlone);
		_settingButton->setMenu(_settingMenu);

		topLayout->addLayout(_buttonLayout, 999);
		topLayout->addSpring();
		topLayout->addSpacer(10);
		topLayout->addWidget(_indexLabel);
		topLayout->addWidget(_xLineEdit);
		topLayout->addWidget(_yLineEdit);
		topLayout->addWidget(_setAxisButton);
		topLayout->addSpacer(10);
		topLayout->addWidget(_fileButton);
		topLayout->addSpacer(3);
		topLayout->addWidget(_contentButton);
		topLayout->addSpacer(3);
		topLayout->addWidget(_settingButton);

		connect(_setAxisButton, Signal_Clicked, &MarkChartView::slotSetAxisButtonClicked);
		connect(_settingButton, Signal_Clicked, &MarkChartView::slotSettingButtonClicked);
	}

	_colorStore.append(BColor(100, 0, 0));
	_colorStore.append(BColor(0, 100, 0));
	_colorStore.append(BColor(0, 0, 100));
	_colorStore.append(BColor(100, 100, 0));
	_colorStore.append(BColor(0, 100, 100));
	_colorStore.append(BColor(100, 0, 100));

	connect(this, Signal_Attached, &MarkChartView::slotSeriesAttached);
	connect(this, Signal_Detached, &MarkChartView::slotSeriesDetached);
	connect(this, Signal_Changed, &MarkChartView::slotParamsChnaged);

}
MarkChartView::~MarkChartView()
{

}

bool MarkChartView::clearMasks()
{
	_markInfos.clear();
	_hoveredIndex = -1;
	_selectedIndex = -1;
	_indexLabel->setText(BString());
	_xLineEdit->setText(BString());
	_yLineEdit->setText(BString());
	this->fresh();
	return true;
}

int MarkChartView::markCount() const
{
	return _markInfos.size();
}
BRealPoint MarkChartView::markRatio(int index) const
{
	return _markInfos(index).ratio;
}

void MarkChartView::createFileMenu()
{
	_fileMenu = new BMenu("file");

	BGroupBox* fileGroupBox = new BGroupBox("file list");
	{
		_fileTable = new BTableWidget();
		_fileTable->setScrollHint(ScrollHint_None);
		_fileTable->setColumnCount(3);
		_fileTable->setColumnLabel(0, "");
		_fileTable->setColumnLabel(1, "file");

		_okButton = new BButton(Form_IconAlone, _fileTable);
		_okButton->setName("okbutton");
		_okButton->hide();

		BButtonGroup* checkButtonGroup = new BButtonGroup();
		BFolder folder("CircleMachine/script");
		if (folder.open())
		{
			for (int i = 0; i < folder.entryCount(); i++)
			{
				BCheckBox* checkBox = new BCheckBox();
				BEntry* entry = folder.entry(i);
				BString filename = entry->path().split('/').at(2);
				_fileTable->addItem(i, 0, checkBox);
				_fileTable->addItem(i, 1, filename);
				checkButtonGroup->addButton(checkBox);
				//connect(checkBox, Signal_Checked, &MarkChartView::slotFileCheckBoxChecked);
			}
			folder.close();
			_fileTable->setColumnWidth(0, 25);
			connect(checkButtonGroup, Signal_Toggled, &MarkChartView::slotCheckButtonGroupToggled);
			connect(_okButton, Signal_Clicked, &MarkChartView::slotOkButtonClicked);
		}

		BHBoxLayout* bottomLayout = new BHBoxLayout();
		bottomLayout->setSpacing(5);
		{
			_deleteButton = new BButton("delete");
			_executeButton = new BButton("execute");

			bottomLayout->addSpring();
			bottomLayout->addWidget(_deleteButton);
			bottomLayout->addWidget(_executeButton);

			connect(_deleteButton, Signal_Clicked, &MarkChartView::slotDeleteButtonClicked);
			connect(_executeButton, Signal_Clicked, &MarkChartView::slotExecuteButtonClicked);
		}

		BVBoxLayout* v_layout = new BVBoxLayout(fileGroupBox);
		v_layout->addWidget(_fileTable);
		v_layout->addLayout(bottomLayout);
	}

	BLayout* layout = new BLayout(_fileMenu);
	layout->setWidget(fileGroupBox);

}
void MarkChartView::createContentMenu()
{
	_contentMenu = new BMenu("Content");

	_contentTable = new BTableWidget();
	_contentTable->setScrollHint(ScrollHint_None);
	_contentTable->setColumnCount(4);
	_contentTable->setColumnLabel(0, "Series");
	_contentTable->setColumnLabel(1, "Name");
	_contentTable->setColumnLabel(2, "Scale");
	_contentTable->setColumnLabel(3, "Unit");

	BCheckBox* checkBox0 = new BCheckBox();
	_contentTable->addItem(0, 0, checkBox0);
	_contentTable->addItem(0, 1, "position");
	_contentTable->addItem(0, 2, "1");
	_contentTable->addItem(0, 3, "um");
	connect(checkBox0, Signal_Checked, &MarkChartView::slotContentCheckBoxChecked);

	BCheckBox* checkBox1 = new BCheckBox();
	_contentTable->addItem(1, 0, checkBox1);
	_contentTable->addItem(1, 1, "feedback");
	_contentTable->addItem(1, 2, "1");
	_contentTable->addItem(1, 3, "um");
	connect(checkBox1, Signal_Checked, &MarkChartView::slotContentCheckBoxChecked);

	BCheckBox* checkBox2 = new BCheckBox();
	_contentTable->addItem(2, 0, checkBox2);
	_contentTable->addItem(2, 1, "difference");
	_contentTable->addItem(2, 2, "1");
	_contentTable->addItem(2, 3, "um");
	connect(checkBox2, Signal_Checked, &MarkChartView::slotContentCheckBoxChecked);

	BCheckBox* checkBox3 = new BCheckBox();
	_contentTable->addItem(3, 0, checkBox3);
	_contentTable->addItem(3, 1, "velocity");
	_contentTable->addItem(3, 2, "1");
	_contentTable->addItem(3, 3, "um/s");
	connect(checkBox3, Signal_Checked, &MarkChartView::slotContentCheckBoxChecked);

	BCheckBox* checkBox4 = new BCheckBox();
	_contentTable->addItem(4, 0, checkBox4);
	_contentTable->addItem(4, 1, "acceleration");
	_contentTable->addItem(4, 2, "1");
	_contentTable->addItem(4, 3, "um/2");
	connect(checkBox4, Signal_Checked, &MarkChartView::slotContentCheckBoxChecked);

	BLayout* layout = new BLayout(_contentMenu);
	layout->setWidget(_contentTable);
}
void MarkChartView::createSettingMenu()
{
	_settingMenu = new BMenu("Setting");
	_settingMenu->setName("setting");

	BGroupBox* timeGroupBox = new BGroupBox("Time");
	{
		BHBoxLayout* topLayout = new BHBoxLayout(timeGroupBox, Part_Top);
		{
			_timeColorButton = new BButton(Graph_Square_Fill);
			topLayout->addSpring();
			topLayout->addWidget(_timeColorButton);
		}

		_timeUnitSpinBox = new BRealSpinBox();
		_timeUnitSpinBox->setValue(this->timeUnit());
		_timeUnitSpinBox->setDecimals(9);

		_timeScaleSpinBox = new BRealSpinBox();
		_timeScaleSpinBox->setValue(this->timeScale());
		_timeScaleSpinBox->setDecimals(9);

		BGridLayout* gridLayout = new BGridLayout(timeGroupBox);
		gridLayout->addWidget(0, 0, new BLabel("Unit"));
		gridLayout->addWidget(0, 1, _timeUnitSpinBox);
		gridLayout->addWidget(1, 0, new BLabel("Scale"));
		gridLayout->addWidget(1, 1, _timeScaleSpinBox);

		connect(_timeColorButton, Signal_Clicked, &MarkChartView::slotTimeColorButtonClicked);
		connect(_timeUnitSpinBox, Signal_EditFinished, &MarkChartView::slotTimeUnitEditFinished);
		connect(_timeScaleSpinBox, Signal_EditFinished, &MarkChartView::slotTimeScaleEditFinished);
	}

	BGroupBox* valueGroupBox = new BGroupBox("Value");
	{
		BHBoxLayout* topLayout = new BHBoxLayout(valueGroupBox, Part_Top);
		{
			_valueColorButton = new BButton(Graph_Square_Fill);
			topLayout->addSpring();
			topLayout->addWidget(_valueColorButton);
		}

		_valueUnitSpinBox = new BRealSpinBox();
		_valueUnitSpinBox->setValue(this->valueUnit());

		_valueScaleSpinBox = new BRealSpinBox();
		_valueScaleSpinBox->setValue(this->valueScale());

		BGridLayout* gridLayout = new BGridLayout(valueGroupBox);
		gridLayout->addWidget(0, 0, new BLabel("Unit"));
		gridLayout->addWidget(0, 1, _valueUnitSpinBox);
		gridLayout->addWidget(1, 0, new BLabel("Scale"));
		gridLayout->addWidget(1, 1, _valueScaleSpinBox);

		connect(_valueColorButton, Signal_Clicked, &MarkChartView::slotValueColorButtonClicked);
		connect(_valueUnitSpinBox, Signal_EditFinished, &MarkChartView::slotValueUnitEditFinished);
		connect(_valueScaleSpinBox, Signal_EditFinished, &MarkChartView::slotValueScaleEditFinished);
	}

	BGroupBox* linesGroupBox = new BGroupBox("Lines");
	{
		_linesWidthSpinBox = new BSpinBox();
		_linesWidthSpinBox->setValue(1);
		_curveCheckBox = new BCheckBox();

		BGridLayout* gridLayout = new BGridLayout(linesGroupBox);
		gridLayout->addWidget(0, 0, new BLabel("width"));
		gridLayout->addWidget(0, 1, _linesWidthSpinBox);
		gridLayout->addWidget(1, 0, new BLabel("Curve"));
		gridLayout->addWidget(1, 1, _curveCheckBox);
		connect(_linesWidthSpinBox, Signal_EditFinished, &MarkChartView::slotLinesWidthEditFinished);
		connect(_curveCheckBox, Signal_Toggled, &MarkChartView::slotLinesCurveChecked);
	}

	BGroupBox* markGroupBox = new BGroupBox("Mark");
	{
		BHBoxLayout* topLayout = new BHBoxLayout(markGroupBox, Part_Top);
		{
			_pointColorButton = new BButton(Graph_Square_Fill);
			_pointColorButton->setColor(200, 100, 0);
			topLayout->addSpring();
			topLayout->addWidget(_pointColorButton);
		}

		_pointSizeSpinBox = new BFloatSpinBox(1, 10);
		_pointSizeSpinBox->setValue(3);

		_circleRadiusSpinBox = new BFloatSpinBox(3, 12);
		_circleRadiusSpinBox->setValue(5);

		_textOffsetEdit = new BLineEdit();
		_textOffsetEdit->setText("10, 10");
		_textOffset.set(10, 10);

		_decimalsSpinBox = new BSpinBox(0, 10);
		_decimalsSpinBox->setValue(this->valueDecimals());

		BGridLayout* gridLayout = new BGridLayout(markGroupBox);
		gridLayout->addWidget(0, 0, new BLabel("point-size"));
		gridLayout->addWidget(0, 1, _pointSizeSpinBox);
		gridLayout->addWidget(1, 0, new BLabel("circle-radius"));
		gridLayout->addWidget(1, 1, _circleRadiusSpinBox);
		gridLayout->addWidget(2, 0, new BLabel("text-offset"));
		gridLayout->addWidget(2, 1, _textOffsetEdit);
		gridLayout->addWidget(3, 0, new BLabel("decimals"));
		gridLayout->addWidget(3, 1, _decimalsSpinBox);

		connect(_pointColorButton, Signal_Clicked, &MarkChartView::slotPointColorButtonClicked);
		connect(_pointSizeSpinBox, Signal_EditFinished, &MarkChartView::slotPointSizeEditFinished);
		connect(_circleRadiusSpinBox, Signal_EditFinished, &MarkChartView::slotCircleRadiusEditFinished);
		connect(_textOffsetEdit, Signal_EditFinished, &MarkChartView::slotTextOffsetEditFinished);
		connect(_decimalsSpinBox, Signal_EditFinished, &MarkChartView::slotDecimalsEditFinished);
	}

	BVBoxLayout* vlayout = new BVBoxLayout(_settingMenu);
	vlayout->addWidget(timeGroupBox);
	vlayout->addWidget(valueGroupBox);
	vlayout->addWidget(linesGroupBox);
	vlayout->addWidget(markGroupBox);
}
void MarkChartView::createCenterMenu()
{
	_centerMenu = new BMenu(this);
	_centerMenu->setName("center");
	_centerMenu->setForm(Form_TextOnly);

	_insertCursorAction = _centerMenu->addAction("Insert Mask");
	_removeCursorAction = _centerMenu->addAction("Remove Mask");
	_removeCursorAction->setEnabled(false);

	connect(_insertCursorAction, Signal_Triggered, &MarkChartView::slotInsertCursorActionTriggered);
	connect(_removeCursorAction, Signal_Triggered, &MarkChartView::slotRemoveCursorActionTriggered);
}
void MarkChartView::freshMarkInfos()
{
	const BRect& area = this->area();
	const BRealRange& valueRange = this->valueRange();
	const BRealRange& timeRange = this->timeRange();
	int decimals = _decimalsSpinBox->value();
	for (int i = 0; i < _markInfos.size(); i++)
	{
		MarkInfo& info = _markInfos[i];
		BReal x = area.left() + info.ratio.x() * area.width();
		BReal y = area.top() + info.ratio.y() * area.height();
		info.visible = true;
		info.point.set(x, y);
		info.time = info.ratio.x() * timeRange.size() + timeRange.min();
		info.value = valueRange.max() - info.ratio.y() * valueRange.size();
		info.text.reset();
		info.text << "time:\t";
		info.text.append(info.time, decimals);
		info.text << '\n';
		info.text << "value:\t";
		info.text.append(info.value, decimals);
	}
}
void MarkChartView::freshMenu()
{
	_removeCursorAction->setEnabled(_selectedIndex >= 0);
}

void MarkChartView::slotSeriesAttached(BObject* object, const BValue& value)
{
	if (Series* series = value)
	{
		int index = this->seriesIndex(series);
		if (series->lineColor().a() == 0)
		{
			const BColor& color = _colorStore.at(index);
			series->setLineColor(color);
		}
		BButton* button = new BButton(series->name());
		button->setCheckable(true);
		button->setForm(Form_IconOnly);
		button->setAsset(series);
		button->setColor(series->lineColor());
		button->setGraph(Graph_Circle_Fill);
		button->setAlign(Align_LeftCenter);
		button->setTips(series->name());
		connect(series, Signal_ColorChanged, &MarkChartView::slotSeriesColorChanged);
		connect(button, Signal_Clicked, &MarkChartView::slotSeriesButtonClicked);
		connect(button, Signal_Framed, &MarkChartView::slotSeriesButtonFramed);
		_buttonLayout->insertWidget(index, button);
	}
}
void MarkChartView::slotSeriesDetached(BObject* object, const BValue& value)
{
	if (Series* series = value)
	{
		for (int i = 0; i < _buttonLayout->count(); i++)
		{
			BWidget* widget = _buttonLayout->widget(i);
			if (widget->asset() == series)
			{
				disconnect(widget, Signal_Clicked);
				_buttonLayout->remove(widget);
				break;
			}
		}
	}
}
void MarkChartView::slotSeriesColorChanged(Series* series, const BValue& value)
{
	for (int i = 0; i < _buttonLayout->count(); i++)
	{
		BObject* object = _buttonLayout->object(i);
		if (object->asset() != series)
			continue;
		BButton* button = dynamic_cast<BButton*>(object);
		if (button)
			button->setColor(series->lineColor());
	}
}

void MarkChartView::slotParamsChnaged(BObject* object, const BValue& value)
{
	_valueScaleSpinBox->setValue(this->valueScale());
	_valueUnitSpinBox->setValue(this->valueUnit());
	_timeScaleSpinBox->setValue(this->timeScale());
	_timeUnitSpinBox->setValue(this->timeUnit());
}
void MarkChartView::slotSeriesButtonClicked(BButton* button, const BValue& value)
{
	const BPoint& pos = value;
	BRect iconRect = button->query("icon-rect");
	if (iconRect.contain(pos))
	{
		const BColor& color = BColorDialog::ChooseColor(this, "Choose Series color", button->color());
		if (button->color() != color)
		{
			button->setColor(color);
			Series* series = button->asset();
			series->setLineColor(color);
			this->fresh();
		}
		return;
	}
	BRect textRect = button->query("text-rect");
	if (textRect.contain(pos))
	{
		Series* series = button->asset();
		bool visible = !series->visible();
		series->setVisible(visible);
		this->fresh();
	}
}
void MarkChartView::slotSeriesButtonFramed(BButton* button, const BValue& value)
{
	Series* series = button->asset();
	if (series->visible())
	{
		BRect textRect = button->query("text-rect");
		textRect.bottom() = (button->height() + textRect.bottom()) / 2;
		BPainter painter(button);
		painter.setColor(button->color());
		painter.drawLine(textRect.leftBottom(), textRect.rightBottom());
	}
}

void MarkChartView::slotSetAxisButtonClicked(BObject* object, const BValue& value)
{
	MarkInfo& info = _markInfos(_selectedIndex);
	BReal time = _xLineEdit->text().toReal();
	BReal yvalue = _yLineEdit->text().toReal();
	info.time = time;
	info.value = yvalue;

	const BRect& area = this->area();
	const BRealRange& valueRange = this->valueRange();
	const BRealRange& timeRange = this->timeRange();
	int decimals = _decimalsSpinBox->value();
	info.ratio.x() = (info.time - timeRange.min()) / timeRange.size();
	info.ratio.y() = (valueRange.max() - info.value) / valueRange.size();
	BReal x = area.left() + info.ratio.x() * area.width();
	BReal y = area.top() + info.ratio.y() * area.height();
	info.visible = true;
	info.point.set(x, y);
	info.text.reset();
	info.text << "time:\t";
	info.text.append(info.time, decimals);
	info.text << '\n';
	info.text << "value:\t";
	info.text.append(info.value, decimals);
	this->fresh();
}
void MarkChartView::slotContentsButtonClicked(BObject* object, const BValue& value)
{

}
void MarkChartView::slotDeleteButtonClicked(BObject* object, const BValue& value)
{
	for (int i = 0; i < _fileTable->rowCount(); i++)
	{
		BTableItem* item0 = _fileTable->item(i, 0);
		BCheckBox* itemCheckBox = (BCheckBox*)item0->widget();
		if (itemCheckBox->checked())
		{
			BTableItem* item1 = _fileTable->item(i, 1);
			BString filename = item1->text();
			BFile::Remove(filename);
			_fileTable->removeRow(i);
			_fileTable->fresh();
		}
	}
}
void MarkChartView::slotExecuteButtonClicked(BObject* object, const BValue& value)
{

}
void MarkChartView::slotFileCheckBoxChecked(BWidget* widget, const BValue& value)
{
	BCheckBox* checkBox = (BCheckBox*)widget;
	if (value == true)
	{
		int c = _fileTable->rowCount();
		for (int i = 0; i < _fileTable->rowCount(); i++)
		{
			BTableItem* item0 = _fileTable->item(i, 0);
			BTableItem* item2 = _fileTable->item(i, 2);
			BCheckBox* itemCheckBox = (BCheckBox*)item0->widget();
			BWidget* itemButton = item2->widget();
			if (checkBox != itemCheckBox)
			{
				itemCheckBox->setChecked(false);
			}
			else
			{
				_fileTable->setColumnVisible(2, true);
				itemButton->setVisible(true);
			}
		}
	}
}
void MarkChartView::slotOkButtonClicked(BObject* object, const BValue& value)
{

}
void MarkChartView::slotCheckButtonGroupToggled(BObject* object, const BValue& value)
{
	BCheckBox* checkBox = value;
	if (checkBox->checked())
	{
		for (int i = 0; i < _fileTable->rowCount(); i++)
		{
			BTableItem* item0 = _fileTable->item(i, 0);
			BCheckBox* itemCheckBox = (BCheckBox*)item0->widget();
			if (checkBox == itemCheckBox)
			{
				BTableItem* item2 = _fileTable->item(i, 2);
				const BRect& crect = _fileTable->centerRect();
				BSize hsize = _okButton->sizeHint();
				BRect itemRect = item0->rect();
				itemRect.right() = crect.right();
				BRect rect = itemRect.align(Align_RightCenter, hsize);
				_okButton->setRect(rect);
				_okButton->show();
				break;
			}
			else
			{
				_okButton->hide();
			}

		}
	}
	else
	{
		_okButton->hide();
	}
}
void MarkChartView::slotContentCheckBoxChecked(BWidget* widget, const BValue& value)
{
	int row = _contentTable->itemOfWidget(widget)->row();
	bool checked = value;
	if (checked)
	{
		const BString& name = _contentTable->item(row, 1)->text();
		const BString& unit = _contentTable->item(row, 3)->text();
		Series* series = new Series();
		series->setName(name);
		series->setUnit(unit);
		_contentTable->setRowAsset(row, series);
	}
	else
	{
		_contentTable->setRowAsset(row, BValue());
	}
	this->clearSeries();
	for (int r = 0; r < _contentTable->rowCount(); r++)
	{
		Series* series = _contentTable->rowAsset(r);
		this->addSeries(series);
	}
}
void MarkChartView::slotSettingButtonClicked(BObject* object, const BValue& value)
{
	_timeColorButton->setColor(this->timeColor());
	_valueColorButton->setColor(this->valueColor());
}

void MarkChartView::slotTimeColorButtonClicked(BObject* object, const BValue& value)
{
	const BColor& color = BColorDialog::ChooseColor("Choose Time graph color", _timeColorButton->color());
	if (_timeColorButton->color() != color)
	{
		_timeColorButton->setColor(color);
		this->fresh();
	}
}
void MarkChartView::slotTimeUnitEditFinished(BObject* object, const BValue& value)
{
	BReal timeUnit = value;
	this->setTimeUnit(timeUnit);
}
void MarkChartView::slotTimeScaleEditFinished(BObject* object, const BValue& value)
{
	BReal timeScale = value;
	this->setTimeScale(timeScale);
}

void MarkChartView::slotValueColorButtonClicked(BObject* object, const BValue& value)
{
	const BColor& color = BColorDialog::ChooseColor(_settingMenu, "Choose Value graph color", _valueColorButton->color());
	if (_valueColorButton->color() != color)
	{
		_valueColorButton->setColor(color);
		this->fresh();
	}
}
void MarkChartView::slotValueUnitEditFinished(BObject* object, const BValue& value)
{
	BReal valueUnit = value;
	this->setValueUnit(valueUnit);
}
void MarkChartView::slotValueScaleEditFinished(BObject* object, const BValue& value)
{
	BReal valueScale = value;
	this->setValueScale(valueScale);
}

void MarkChartView::slotLinesWidthEditFinished(BObject* object, const BValue& value)
{
	int lineWidth = value;
	for (int i = 0; i < this->seriesCount(); i++)
	{
		Series* series = this->series(i);
		series->setLineWidth((float)lineWidth);
	}
	this->fresh();
}
void MarkChartView::slotLinesCurveChecked(BObject* object, const BValue& value)
{

}

void MarkChartView::slotPointColorButtonClicked(BObject* object, const BValue& value)
{
	const BColor& color = BColorDialog::ChooseColor(_settingMenu, "Choose Lines graph color", _pointColorButton->color());
	if (_pointColorButton->color() != color)
	{
		_pointColorButton->setColor(color);
		this->fresh();
	}
}
void MarkChartView::slotPointSizeEditFinished(BObject* object, const BValue& value)
{
	this->fresh();
}
void MarkChartView::slotTextOffsetEditFinished(BObject* object, const BValue& value)
{
	const BString& text = value;
	BStringArray words = text.split(',');
	if (words.size() == 2)
	{
		_textOffset.x() = words[0].toInt();
		_textOffset.y() = words[1].toInt();
		this->fresh();
	}
}
void MarkChartView::slotCircleRadiusEditFinished(BObject* object, const BValue& value)
{
	this->fresh();
}
void MarkChartView::slotDecimalsEditFinished(BObject* object, const BValue& value)
{
	int decimals = value;
	this->setValueDecimals(decimals);
	freshMarkInfos();
	this->fresh();
}

void MarkChartView::slotInsertCursorActionTriggered(BObject* object, const BValue& value)
{
	MarkInfo& info = _markInfos.append();
	BRect area = this->area();
	BPoint pos = _centerMenu->pos();
	info.ratio.x() = BReal(pos.x() - area.min().x()) / area.width();
	info.ratio.y() = BReal(pos.y() - area.min().y()) / area.height();
	freshMarkInfos();
	this->fresh();
	this->emit("insert-mark");
}
void MarkChartView::slotRemoveCursorActionTriggered(BObject* object, const BValue& value)
{
	if (_markInfos.remove(_selectedIndex))
	{
		this->fresh();
		this->emit("remove-mark");
	}
}

void MarkChartView::scrolling(Orientation orientation)
{
	ChartView::scrolling(orientation);
	freshMarkInfos();
}

void MarkChartView::resizeEvent(const BEvent& event)
{
	ChartView::resizeEvent(event);
}

void MarkChartView::styleEvent(const BEvent& event)
{
	ChartView::styleEvent(event);

	int fsize = this->realFont()->size();
	this->setPerch(Part_Top, fsize);
	this->setMargin(Part_Left, fsize);
	this->setMargin(Part_Bottom, fsize);

	const BStyle* style = event.value();
	_timeColorButton->setColor(style->color(Color_Text));
	_valueColorButton->setColor(style->color(Color_Text));
	_contentButton->setIcon(style->icon("contents"));
	_tipsStyle = style->annex("tips");
}
void MarkChartView::freshEvent(const BEvent& event)
{
	ChartView::freshEvent(event);
	//scrolling(Orientation_Crossing);
	hintValueUnit();
	hintTimeUnit();
}
void MarkChartView::paintEvent(const BEvent& event)
{
	ChartView::paintEvent(event);

	BPainter painter(this);

	const BMargin& margin = this->margin();
	const BRect& crect = this->centerRect();
	const BRect& area = this->area();

	const BString& name = this->name();
	if (name.size())
	{
		BRect nameArea = this->rect(Part_Top);
		nameArea.top() = nameArea.bottom();
		nameArea.bottom() = crect.top();
		painter.setColor(Color_Text);
		painter.drawText(nameArea, name, Align_Center);
	}

	painter.setClip(crect);
	painter.setStyle(_tipsStyle);
	for (int i = 0; i < _markInfos.size(); i++)
	{
		MarkInfo& info = _markInfos[i];
		BPointd point = info.point;

		State state = State_Normal;
		State horHandState = State_Normal;
		State verHandState = State_Normal;
		if (_hoveredIndex == i)
		{
			if (_leftPressed)
			{
				if (_hoverOrientation & Orientation_Horizontal)
					horHandState |= State_Pressed;
				if (_hoverOrientation & Orientation_Vertical)
					verHandState |= State_Pressed;
			}
			else
			{
				if (_hoverOrientation & Orientation_Horizontal)
					horHandState |= State_Hovered;
				if (_hoverOrientation & Orientation_Vertical)
					verHandState |= State_Hovered;
			}
		}
		else
		{
			if (_selectedIndex == i)
			{
				state = State_Checked;
			}
		}
		double radius = _circleRadiusSpinBox->value();
		painter.setColor(Color_Handle, state);
		painter.drawCircle(point, radius);
		if (_leftPressed && _catchPointMap.size())
		{
			painter.setColor(255, 100, 0);
			painter.setPointSize(_pointSizeSpinBox->value() * 2);
			painter.drawPoint(_catchPointMap.first());
			const BRealLine& line = _catchLineMap.first();
			painter.drawLine(line.begin().x(), line.begin().y(), line.end().x(), line.end().y());
		}

		painter.setColor(_pointColorButton->color());
		painter.setPointSize(_pointSizeSpinBox->value());
		painter.setPointSmooth(true);
		painter.drawPoint(point);

		painter.setLineStipple(0xf0f0);
		{
			painter.setColor(Color_Handle, horHandState);
			painter.drawLine(point.x(), (double)crect.top(), point.x(), point.y() - radius);
			painter.drawLine(point.x(), (double)crect.bottom(), point.x(), point.y() + radius);
			painter.setColor(Color_Handle, verHandState);
			painter.drawLine((double)crect.left(), point.y(), point.x() - radius, point.y());
			painter.drawLine((double)crect.right(), point.y(), point.x() + radius, point.y());
		}
		painter.setLineStipple(0x0000);

		BSize textSize = painter.realFont()->textSize(info.text);
		BRect textRect(point + _textOffset, textSize);
		BRect textArea = textRect % 110;
		textArea.right() += painter.realFont()->size();

		painter.setPolySmooth(true);
		painter.setColor(Color_Background);
		painter.drawRoundRect(textArea);
		painter.fillRoundRect(textArea);
		painter.setPolySmooth(false);

		BRect numRect = textArea.align(Align_Left, BSize(painter.realFont()->size(), textArea.height()));
		painter.setColor(255, 128, 128, 200);
		painter.fillRoundRect(numRect);
		painter.setColor(Color_Text);
		painter.drawText(numRect, BString(i + 1), Align_Center);

		textRect.move(numRect.width(), 0);
		painter.setColor(Color_Text);
		painter.drawText(textRect, info.text);

	}

}

void MarkChartView::mouseEnterEvent(const BMouseEvent& mouseEvent)
{
	ChartView::mouseLeaveEvent(mouseEvent);
	_hoveredIndex = -1;
	_leftPressed = false;
}
void MarkChartView::mouseLeaveEvent(const BMouseEvent& mouseEvent)
{
	ChartView::mouseLeaveEvent(mouseEvent);
	_hoveredIndex = -1;
	_leftPressed = false;
}

void MarkChartView::mousePressEvent(const BMouseEvent& mouseEvent)
{
	if (mouseEvent.button() == Button_Left)
	{
		if (_hoveredIndex > -1)
		{
			_leftPressed = true;
			this->fresh();
			return;
		}
	}
	ChartView::mousePressEvent(mouseEvent);
}
void MarkChartView::mouseReleaseEvent(const BMouseEvent& mouseEvent)
{
	if (mouseEvent.button() == Button_Left)
	{
		if (_leftPressed)
		{
			_leftPressed = false;
			this->fresh();
			return;
		}
	}
	ChartView::mouseReleaseEvent(mouseEvent);
}

void MarkChartView::mouseMoveEvent(const BMouseEvent& mouseEvent)
{
	ChartView::mouseMoveEvent(mouseEvent);
	BRealPoint pos = mouseEvent.pos();
	const BRect& crect = this->centerRect();
	const BRect& area = this->area();
	if (_leftPressed)
	{
		_catchPointMap.reset();
		_catchLineMap.reset();
		MarkInfo& info = _markInfos[_hoveredIndex];
		if (BSystem::KeyState(Key_Ctrl))
		{
			double radius = _circleRadiusSpinBox->value();
			if (_hoverOrientation == Orientation_Crossing)
			{
				BVector point(pos.x(), pos.y(), 0);
				for (int s = 0; s < this->seriesCount(); s++)
				{
					const BPointfArray& points = this->seriesLines(s);
					for (int i = 1; i < points.size(); i++)
					{
						const BPointf& p0 = points[i - 1];
						const BPointf& p1 = points[i];
						if (pos.x() < p0.x() || pos.x() > p1.x())
							continue;
						BLine line(p0.x(), p0.y(), 0, p1.x(), p1.y(), 0);
						BVector res = line.closest(point);
						BReal dist = (res - point).length();
						if (dist < radius)
						{
							_catchPointMap.insert(dist, BRealPoint(res.x(), res.y()));
							_catchLineMap.insert(dist, BRealLine(p0.x(), p0.y(), 0, p1.x(), p1.y(), 0));
							break;
						}
					}
				}
			}
			if (_hoverOrientation == Orientation_Vertical)
			{
				pos.x() = info.point.x();
				for (int s = 0; s < this->seriesCount(); s++)
				{
					const BPointfArray& points = this->seriesLines(s);
					for (int i = 1; i < points.size(); i++)
					{
						const BPointf& p0 = points[i - 1];
						const BPointf& p1 = points[i];
						if (pos.x() < p0.x() || pos.x() > p1.x())
							continue;
						BReal dx = p1.x() - p0.x();
						BReal dy = p1.y() - p0.y();
						BReal y = (dy * (pos.x() - p0.x())) / dx + p0.y();
						BReal dist = abs(pos.y() - y);
						if (dist < radius)
						{
							_catchPointMap.insert(dist, BRealPoint(pos.x(), y));
							_catchLineMap.insert(dist, BRealLine(p0.x(), p0.y(), 0, p1.x(), p1.y(), 0));
							break;
						}
					}
				}
			}
			if (_hoverOrientation == Orientation_Horizontal)
			{
				pos.y() = info.point.y();
				for (int s = 0; s < this->seriesCount(); s++)
				{
					const BPointfArray& points = this->seriesLines(s);
					for (int i = 1; i < points.size(); i++)
					{
						const BPointf& p0 = points[i - 1];
						const BPointf& p1 = points[i];
						if (pos.x() < p0.x() || pos.x() > p1.x())
							continue;
						BReal dx = p1.x() - p0.x();
						BReal dy = p1.y() - p0.y();
						BReal x = (dx * (pos.y() - p0.y())) / dy + p0.x();
						BReal dist = abs(pos.x() - x);
						if (dist < radius)
						{
							_catchPointMap.insert(dist, BRealPoint(x, pos.y()));
							_catchLineMap.insert(dist, BRealLine(p0.x(), p0.y(), 0, p1.x(), p1.y(), 0));
							break;
						}
					}
				}
			}
		}
		if (_catchPointMap.size())
		{
			pos = _catchPointMap.first();
		}
		if (_hoverOrientation & Orientation_Horizontal)
			info.ratio.x() = BReal(pos.x() - area.min().x()) / area.width();
		if (_hoverOrientation & Orientation_Vertical)
			info.ratio.y() = BReal(pos.y() - area.min().y()) / area.height();
		freshMarkInfos();
		this->fresh();
		this->emit("move-mark", _hoveredIndex);
	}
	else
	{
		Orientation orientation = Orientation_None;
		int hoveredIndex = -1;
		if (crect.contain(pos))
		{
			for (int i = 0; i < _markInfos.size(); i++)
			{
				MarkInfo& info = _markInfos[i];
				if (!info.visible)
					continue;
				double hdist = abs(info.point.x() - pos.x());
				double vdist = abs(info.point.y() - pos.y());
				if (hdist < 10)
					orientation |= Orientation_Horizontal;
				if (vdist < 10)
					orientation |= Orientation_Vertical;
				if (orientation)
				{
					hoveredIndex = i;
					break;
				}
			}
		}
		if (_hoveredIndex != hoveredIndex || _hoverOrientation != orientation)
		{
			_hoveredIndex = hoveredIndex;
			_hoverOrientation = orientation;
			if (_hoveredIndex > -1)
			{
				if (orientation == Orientation_Horizontal)
					this->setCursor(Cursor_SizeHor);
				if (orientation == Orientation_Vertical)
					this->setCursor(Cursor_SizeVer);
				if (orientation == Orientation_Crossing)
					this->setCursor(Cursor_None);
			}
			else
			{
				this->setCursor(Cursor_None);
			}
			this->fresh();
		}
	}
}
void MarkChartView::mouseClickEvent(const BMouseEvent& mouseEvent)
{
	ChartView::mouseClickEvent(mouseEvent);
	if (mouseEvent.button() == Button_Left)
	{
		if (_selectedIndex != _hoveredIndex)
		{
			_selectedIndex = _hoveredIndex;
			if (_selectedIndex < 0)
			{
				_indexLabel->setText(BString());
				_xLineEdit->setText(BString());
				_yLineEdit->setText(BString());
			}
			else
			{
				_indexLabel->setText(_selectedIndex + 1);
				_xLineEdit->setText(_markInfos(_selectedIndex).time);
				_yLineEdit->setText(_markInfos(_selectedIndex).value);
				this->fresh();
				freshMenu();
			}
			this->fresh();
		}
	}
	if (mouseEvent.button() == Button_Right)
	{
		const BPoint& pos = mouseEvent.pos();
		if (this->centerRect().contain(pos))
		{
			_centerMenu->setPos(pos);
			_centerMenu->popup();
		}
	}
}
